// 2024年5月5日
// Mechanicoder

#include <QObject>

#include <AIS_InteractiveContext.hxx>
#include <AIS_InteractiveObject.hxx>
#include <TopoDS_Shape.hxx>
#include <NCollection_String.hxx>

#include <memory>

class ModelList;
struct Params;
class Geom_BezierCurve;
class Geom2d_BezierCurve;
class Geom_Surface;
class TopoDS_Face;
class TopoDS_Edge;

class FanMaker : public QObject
{
    Q_OBJECT

public:
    FanMaker(QObject* parent, ModelList* ms);
    ~FanMaker();

    void Display(Handle(AIS_InteractiveContext) context);

public slots:
    void OnLeftButtonClicked(double x, double y, double z);
    void OnKeyPressed(int key); // 鼠标交互存在问题，改用按钮
private:
    void MakeBase() const;

    void MakeVerticalColumn() const;

    void MakeButtons() const;

    void MakeShell() const;

    // 风扇旋转中心、参考坐标系
    gp_Ax2 FanRevolLocBase() const;

    TopoDS_Shape MakeShellFrontRevol(const gp_Ax1& revol_axis) const;

    void MakeFan() const;

    TopoDS_Shape MakeFanHub() const;

    TopoDS_Shape MakeRuledBlade() const;

    TopoDS_Shape MakeBlade() const;
        
    Handle(Geom_Surface) MakeBladeSectionSurf(double height, double half_width,
        double hub_ymin, double hub_ymax) const;
    
    // 构造截面线等参数点
    std::vector<gp_Pnt2d> MakeBladeSectionUVs(double angle, double thick) const;
    
    // 获取面上的三维点
    std::vector<gp_Pnt> GetPntsOnSurf(const Handle(Geom_Surface)& surf, const std::vector<gp_Pnt2d>& uvs) const;

    // 拟合 B 样条曲面
    Handle(Geom_Surface) ApproxSurf(const std::vector<std::vector<gp_Pnt>>& pnts) const;

    void MakeFrontCover() const;

    void MakeBackCover() const;

    // 字体
    void MakeText() const;

    // 根据控制点构造 Bezier 曲线
    Handle(Geom_BezierCurve) MakeBezier(const std::vector<gp_Pnt>& poles) const;
    Handle(Geom2d_BezierCurve) MakeBezier(const std::vector<gp_Pnt2d>& poles) const;

    Quantity_Color Color(int r, int g, int b) const;

    TopoDS_Shape Fuse(const std::vector<TopoDS_Shape>& shapes) const;
    TopoDS_Shape Cut(const TopoDS_Shape& s, const TopoDS_Shape& cutter) const;
    TopoDS_Shape Cut(const TopoDS_Shape& s, const std::vector<TopoDS_Shape>& cutter) const;
    TopoDS_Shape Compound(const std::vector<TopoDS_Shape>& shapes) const;

    TopoDS_Shape PrismText(const NCollection_String& text, const gp_Ax2& loc,
        const gp_Vec& prism_vec, int pt_size = 12) const;

    TopoDS_Shape MakeCylinder(const gp_Ax2& loc, double radius, double h_positive,
        double h_negative = 0) const;

    // 构造面
    TopoDS_Face MakeFace(const std::vector<TopoDS_Edge>& edges) const;

    // 拉伸
    TopoDS_Shape Extrude(const std::vector<TopoDS_Edge>& edges, const gp_Vec& vec) const;

    // 旋转
    TopoDS_Shape Revolve(const std::vector<TopoDS_Edge>& edges, const gp_Ax1& axis) const;

    // 360度圆周阵列
    TopoDS_Shape CircularPattern(const TopoDS_Shape& shape, const gp_Ax1& axis, int num) const;

    // 对最长的 <longest_most> 条边进行倒圆
    TopoDS_Shape Fillet(const TopoDS_Shape& shape, double radius, int longest_most = 2) const;

    // 按钮被按下后
    void OnButtonClicked(size_t button);

    // 风扇运行
    void OnFanRunning();

    Handle(AIS_InteractiveObject) DisplayShape(const TopoDS_Shape& shape, const QString& name,
        const Quantity_Color& color = Quantity_Color()) const;
    Handle(AIS_InteractiveObject) DisplayBlades(const std::vector<TopoDS_Shape>& blades) const;

    void DisplayPnts(const std::vector<gp_Pnt>& pnts, const QString& name) const;

private:
    Handle(AIS_InteractiveContext) _context;

    // 四个按钮：0， 1， 2， 3
    mutable std::vector<Handle(AIS_InteractiveObject)> _buttons;
    size_t _prevButton;

    // 风扇
    mutable Handle(AIS_InteractiveObject) _fan;
    int _fanRPM;

    TopoDS_Shape _base;

    bool _isDone;

    std::shared_ptr<Params> _d;
};